package org.biogroovy.io.sulab

import groovy.json.JsonSlurper

import org.biogroovy.conf.BioGroovyConfig
import org.biogroovy.io.AbsJsonSeqFetcher
import org.biogroovy.io.IFetcher;
import org.biogroovy.models.Protein
import org.biogroovy.models.ProteinDomain
import org.biogroovy.net.URLMap


/**
 * The MyGene.info site contains protein as well as gene information. This fetcher
 * handles getting all protein-related information.
 */
class MyProteinInfoFetcher extends AbsJsonSeqFetcher<Protein> {

	private static final String DATABASE_NAME="mygeneinfo";
	private static final String URL_TEMPLATE = "http://mygene.info/v2/query?q=entrezgene:id";

	private Map<String, String> paramMap = ["fields":"all"];

	private String email = null;

	/**
	 * Constructor
	 */
	public MyProteinInfoFetcher() {
		this.databaseName = DATABASE_NAME;
		init();
	}

	/**
	 * Constructor.
	 * @param paramMap a map of parameter names an values
	 */
	public MyProteinInfoFetcher(Map<String, String> paramMap) {
		super(paramMap);
		init();
	}
	
	private void init() {
		ConfigObject conf = BioGroovyConfig.getConfig()
		this.email = conf.mygeneinfo.email
	}


	@Override
	public void parse(Protein pojo, Map jsonMap) {
		super.parse(pojo, jsonMap);
		parseDomains(pojo, jsonMap);
		parsePathways(pojo, jsonMap);
		parseEnsemblIds(pojo, jsonMap);
	}

	protected void parseEnsemblIds(Protein protein, Map jsonMap){
		jsonMap.ensembl.protein.each{it ->
			protein.ensemblIds.add(it)
		}
	}

	protected void parseReferences(Protein protein, Map jsonMap) {
		super.parseReferences(protein, jsonMap);
		protein.references.put("pir", jsonMap.pir);
		protein.uniprotAccession = jsonMap.uniprot."Swiss-Prot"
	}

	/**
	 * This method parses the domains for the protein.
	 * @param protein the protein being annotated
	 * @param jsonMap the map derived from the jsonObject.
	 */
	protected void parseDomains(Protein protein, Map jsonMap){

		def node = jsonMap.'interpro'
		if(node != null){
			if(node instanceof ArrayList){
				jsonMap.'interpro'.each{it ->
					protein.domains.add(new ProteinDomain(database: 'interpro', domainId:it.id, shortDesc:it.short_desc, desc:it.desc))
				}
			}else {
				protein.domains.add(new ProteinDomain(database:'interpro',domainId:node.id, shortDesc:node.short_desc, desc:node.desc))
			}
		}
	}



	@Override
	public Protein fetch(String id) throws IOException {
		URL url = getUrl(id, null);
		Protein protein = read(url.openStream())
		return protein;
	}

	@Override
	public URL getUrl(String id, Map<String, String> paramMap) {
		
		String url = URL_TEMPLATE.replace("id", id)
		
		
		Map<String, String> map = [email:this.email]
		if (paramMap != null) {
			map.putAll(paramMap);
		}
		map.putAll(this.paramMap)
		
		
		URLMap urlMap = new URLMap(url, map);
		return new URL(urlMap.toString());
		
	}

	@Override
	public List<Protein> fetchAll(String id) throws IOException {

		String[] idArray = id.split(",")	
		
		Protein protein = null;
		List<Protein> Protein = new ArrayList<>();
		idArray.each{String currId ->
			protein = fetch(currId.trim());
			Protein.add(protein)
		}
		
		return Protein;

		
	}

	@Override
	protected void parseRefSeqs(Protein pojo, Map jsonMap) {
		pojo.refSeqAcc = jsonMap.refseq.protein.join(",");
	}

	@Override
	public Protein read(InputStream inputStream) throws IOException {
		JsonSlurper slurper = new JsonSlurper();
		Map<String, String> obj = (Map)slurper.parse(inputStream);

		Protein protein = new Protein();
		parse(protein, obj?.hits[0])
		return protein
	}

	@Override
	public List<Protein> readList(InputStream inputStream) throws IOException {
		JsonSlurper slurper = new JsonSlurper();
		Map<String, String> obj = (Map)slurper.parse(inputStream);

		List<Protein> proteinList = new ArrayList<Protein>();
		obj.hits.each{Map prop ->
			Protein protein = new Protein();
			parse(protein, prop)
			proteinList.add(protein)
		}
		return proteinList
	}

	@Override
	public IFetcher<Protein> getNewInstance() {
		return new MyProteinInfoFetcher();
	}
}
